#include "rated_limit.h"
#include "msg_queue_interface.h"
#include "msg_queue_pid_define.h"
#include "function_interface.h"
#include "fpga_addr_define.h"
#include "utils.h"
#include "debug.h"
#include <stdlib.h>
#include "debug.h"
#include <pthread.h>
#include <unistd.h>
#include <sys/syscall.h>
#include "misc.h"
#include <syslog.h>
#include "utils.h"


#define PERCENT_UPLMT                   (1.0F) /* 百分比上限 */
#define RATED_LIMIT_REASON_GROUP_QTY    (RATED_LIMIT_OWNER_QTY / 16 + 1)


typedef struct
{
    uint16_t ratedLimitReason[RATED_LIMIT_REASON_GROUP_QTY]; /* 限额原因 */
    float ratedLimitPercentage[RATED_LIMIT_OWNER_QTY];       /* 详细限额百分比 */
    float entirePercentage;                                  /* 整体限额百分比 */
} ratedLimit_t;


#if(RATED_LIMIT_TYPE_SEL == RATED_LIMIT_TYPE_ENTIRE)


static ratedLimit_t ratedLimit;


/**
 * @brief 数据初始化
 */
void RatedLimit_Init(void)
{
    uint16_t idx;
    
    for(idx = 0; idx < RATED_LIMIT_OWNER_QTY; idx++)
    {
        ratedLimit.ratedLimitPercentage[idx] = PERCENT_UPLMT;
    }
}


/**
 * @brief 获取限额百分比
 */
int RatedLimit_GetPercentage(uint16_t *pValue)
{
    *pValue = (uint16_t)(ratedLimit.entirePercentage * 100);
    return 0;
}


/**
 * @brief 获取限额原因
 */
int RatedLimit_GetReason(uint16_t group, uint16_t *pValue)
{
    if(group >= RATED_LIMIT_REASON_GROUP_QTY)
    {
        PRINT_WARN("Parameter error[%d]", group);
        return -1;
    }

    *pValue = ratedLimit.ratedLimitReason[group];
    return 0;
}


/**
 * @brief 设置限额百分比
 */
int RatedLimit_SetPercentage(ratedLimitOwner_t owner, float percentage)
{
    int err, msgId;
    uint16_t group, bitVal;

    if(owner >= RATED_LIMIT_OWNER_QTY ||
       percentage > PERCENT_UPLMT)
    {
        PRINT_WARN("Parameter error[%d][%f]", owner, percentage);
        return -1;
    }

    if((err = MsgQueue_Get(MSG_QUEUE_PID_RATED_LIMIT, &msgId)) < 0)
	{
        // PRINT_ERROR("Get error[%d]", err);
		return -2;
	}

    ratedLimit.ratedLimitPercentage[owner] = percentage;
    group = (uint16_t)(owner / 16);
    bitVal = (uint16_t)(owner % 16);
    FltCmp_IsEqual(percentage, PERCENT_UPLMT) ? \
        CLEAR_BIT(ratedLimit.ratedLimitReason[group], bitVal) : \
        SET_BIT(ratedLimit.ratedLimitReason[group], bitVal);

    // PRINT_DEBUG("(%d) limits rated to [%.3f]", owner, percentage);
    // syslog(LOG_INFO, "%s: (%d) limits rated to [%.3f]", __func__, owner, percentage);

    if((err = MsgQueue_Send1(msgId, "1")) < 0)
    {
        PRINT_WARN("Send error[%d]", err);
        return -3;
    }

    return 0;
}


/**
 * @brief 刷新限额百分比
 */
static int RatedLimit_Refresh(int *pFlag)
{   
    uint16_t idx;
    float pAcRated = 0.0F, lmtPwr_1kW = 0.0F, percentage;

    for(idx = 0, percentage = PERCENT_UPLMT; idx < RATED_LIMIT_OWNER_QTY; idx++)
    {
        percentage = FltCmp_IsALessThanB(ratedLimit.ratedLimitPercentage[idx], percentage) ? ratedLimit.ratedLimitPercentage[idx] : percentage;
    }

    if(FltCmp_IsNotEqual(ratedLimit.entirePercentage, percentage))
    {
        PRINT_DEBUG("Limits rated from [%.3f] to [%.3f]", ratedLimit.entirePercentage, percentage);
        syslog(LOG_INFO, "%s: Limits rated from [%.3f] to [%.3f]", __func__, ratedLimit.entirePercentage, percentage);
        ratedLimit.entirePercentage = percentage;
        FuncInf_GetRatedPwr(NULL, &pAcRated);
        lmtPwr_1kW = pAcRated * percentage;
        if(*pFlag != 0)
        {
            *pFlag = 0;
            FuncInf_SetLimit(FUNCINF_OPERATOR_INIT, FUNCINF_LMT_TYPE_AC_PWR_CHRG, (-1) * lmtPwr_1kW);
            FuncInf_SetLimit(FUNCINF_OPERATOR_INIT, FUNCINF_LMT_TYPE_AC_PWR_DISC, lmtPwr_1kW);
        }
        else
        {
            FuncInf_SetLimit(FUNCINF_OPERATOR_RATED_LIMIT, FUNCINF_LMT_TYPE_AC_PWR_CHRG, (-1) * lmtPwr_1kW);
            FuncInf_SetLimit(FUNCINF_OPERATOR_RATED_LIMIT, FUNCINF_LMT_TYPE_AC_PWR_DISC, lmtPwr_1kW);
        }
        PRINT_DEBUG("lmtPwr_1kW[%.2f]", lmtPwr_1kW);
        syslog(LOG_INFO, "%s: lmtPwr_1kW[%.2f]", __func__, lmtPwr_1kW);
    }

    return 0;
}


void RatedLimit_Thread(void *pPara)
{
    Misc_InitThread(__func__);

    int err, msgId, msgDataNum, firstFlag = 1;
    char msgData[MSG_DATA_LEN] = {0};

    if((err = MsgQueue_Get(MSG_QUEUE_PID_RATED_LIMIT, &msgId)) < 0)
	{
        // PRINT_ERROR("Get error[%d]", err);
		return;
	}

    MsgQueue_Send1(msgId, "1");

    while(1)
    {
        if((err = MsgQueue_Recv1(msgId, msgData)) < 0)
        {
            // PRINT_ERROR("Recv error[%d]", err);
        }
        // PRINT_DEBUG();
        msgDataNum = atoi(msgData);
        switch(msgDataNum)
        {
            case 1:
                RatedLimit_Refresh(&firstFlag); 
                break;

            default:
                PRINT_WARN("error msgDataNum[%d]", msgDataNum);
                break;
        }
    }
}


#elif(RATED_LIMIT_TYPE_SEL == RATED_LIMIT_TYPE_SEPARATE)


static ratedLimit_t ratedLimit[RATED_LIMIT_TYPE_QTY] = {0};


/**
 * @brief 数据初始化
 */
void RatedLimit_Init(void)
{
    uint16_t i, idx;

    for(i = 0; i < RATED_LIMIT_TYPE_QTY; i++)
    {
        for(idx = 0; idx < RATED_LIMIT_OWNER_QTY; idx++)
        {
            ratedLimit[i].ratedLimitPercentage[idx] = PERCENT_UPLMT;
        }
    }
}


/**
 * @brief 获取限额百分比
 */
int RatedLimit_GetPercentage(ratedLimitType_t type, uint16_t *pValue)
{   
    if(type >= RATED_LIMIT_TYPE_QTY)
    {
        PRINT_WARN("Parameter error[%d]", type);
        return -1;
    }
    
    *pValue = (uint16_t)(ratedLimit[type].entirePercentage * 100);
    return 0;
}


/**
 * @brief 获取限额原因
 */
int RatedLimit_GetReason(ratedLimitType_t type, uint16_t group, uint16_t *pValue)
{
    if(type >= RATED_LIMIT_TYPE_QTY || \
       group >= RATED_LIMIT_REASON_GROUP_QTY)
    {
        PRINT_WARN("Parameter error[%d][%d]", type, group);
        return -1;
    }

    *pValue = ratedLimit[type].ratedLimitReason[group];
    return 0;
}


/**
 * @brief 设置限额百分比
 */
int RatedLimit_SetPercentage(ratedLimitOwner_t owner, ratedLimitType_t type, float percentage)
{
    int err, msgId;
    uint16_t group, bitVal;

    if(owner >= RATED_LIMIT_OWNER_QTY || \
       type >= RATED_LIMIT_TYPE_QTY || \
       percentage > PERCENT_UPLMT)
    {
        PRINT_WARN("Parameter error[%d][%d][%f]", owner, type, percentage);
        return -1;
    }

    if((err = MsgQueue_Get(MSG_QUEUE_PID_RATED_LIMIT, &msgId)) < 0)
	{
        // PRINT_ERROR("Get error[%d]", err);
		return -2;
	}

    ratedLimit[type].ratedLimitPercentage[owner] = percentage;
    group = (uint16_t)(owner / 16);
    bitVal = (uint16_t)(owner % 16);
    FltCmp_IsEqual(percentage, PERCENT_UPLMT) ? \
        CLEAR_BIT(ratedLimit[type].ratedLimitReason[group], bitVal) : \
        SET_BIT(ratedLimit[type].ratedLimitReason[group], bitVal);

    switch(type)
    {
        case RATED_LIMIT_TYPE_CHRG:
            PRINT_DEBUG("(%d) limits rated to [%.3f](Charge)", owner, percentage);
            if((err = MsgQueue_Send1(msgId, "1")) < 0)
            {
                PRINT_WARN("Send error[%d]", err);
                return -3;
            }
            break;

        case RATED_LIMIT_TYPE_DISC:
            PRINT_DEBUG("(%d) limits rated to [%.3f](Discharge)", owner, percentage);
            if((err = MsgQueue_Send1(msgId, "2")) < 0)
            {
                PRINT_WARN("Send error[%d]", err);
                return -3;
            }
            break;
        
        default:
            PRINT_WARN("Parameter error[%d]", type);
            return -1;
    }

    return 0;
}


/**
 * @brief 刷新限额百分比
 */
static int RatedLimit_Refresh(ratedLimitType_t type, int *pFlag))
{   
    uint16_t idx;
    float pAcRated = 0.0F, lmtPwr_1kW = 0.0F, percentage;

    if(type >= RATED_LIMIT_TYPE_QTY)
    {
        PRINT_WARN("Parameter error[%d]", type);
        return -1;
    }

    for(idx = 0, percentage = PERCENT_UPLMT; idx < RATED_LIMIT_OWNER_QTY; idx++)
    {
        percentage = FltCmp_IsALessThanB(ratedLimit[type].ratedLimitPercentage[idx], percentage) ? ratedLimit[type].ratedLimitPercentage[idx] : percentage;
    }

    switch(type)
    {
        case RATED_LIMIT_TYPE_CHRG:
            if(FltCmp_IsNotEqual(ratedLimit[type].entirePercentage, percentage))
            {
                PRINT_DEBUG("Limits rated from [%.3f] to [%.3f](Charge)", ratedLimit[type].entirePercentage, percentage);
                ratedLimit[type].entirePercentage = percentage;
                FuncInf_GetRatedPwr(NULL, &pAcRated);
                lmtPwr_1kW = pAcRated * percentage;
                if(*pFlag != 0)
                {
                    *pFlag = 0;
                    FuncInf_SetLimit(FUNCINF_OPERATOR_INIT, FUNCINF_LMT_TYPE_AC_PWR_CHRG, (-1) * lmtPwr_1kW);
                }
                else
                {
                    FuncInf_SetLimit(FUNCINF_OPERATOR_RATED_LIMIT, FUNCINF_LMT_TYPE_AC_PWR_CHRG, (-1) * lmtPwr_1kW);
                }
                PRINT_DEBUG("lmtPwr_1kW[%.2f]", lmtPwr_1kW);
            }
            break;

        case RATED_LIMIT_TYPE_DISC:
            if(FltCmp_IsNotEqual(ratedLimit[type].entirePercentage, percentage))
            {
                PRINT_DEBUG("Limits rated from [%.3f] to [%.3f](Discharge)", ratedLimit[type].entirePercentage, percentage);
                ratedLimit[type].entirePercentage = percentage;
                FuncInf_GetRatedPwr(NULL, &pAcRated);
                lmtPwr_1kW = pAcRated * percentage;
                if(*pFlag != 0)
                {
                    *pFlag = 0;
                    FuncInf_SetLimit(FUNCINF_OPERATOR_INIT, FUNCINF_LMT_TYPE_AC_PWR_DISC, lmtPwr_1kW);
                }
                else
                {
                    FuncInf_SetLimit(FUNCINF_OPERATOR_RATED_LIMIT, FUNCINF_LMT_TYPE_AC_PWR_DISC, lmtPwr_1kW);
                }
                PRINT_DEBUG("lmtPwr_1kW[%.2f]", lmtPwr_1kW);
            }
            break;
        
        default:
            PRINT_WARN("Parameter error[%d]", type);
            return -1;
    }

    return 0;
}


void RatedLimit_Thread(void *pPara)
{
    Misc_InitThread(__func__);

    int err, msgId, msgDataNum, firstFlagChrg = 1, firstFlagDisc = 1;
    char msgData[MSG_DATA_LEN] = {0};

    if((err = Get(MSG_QUEUE_PID_RATED_LIMIT, &msgId)) < 0)
	{
        PRINT_ERROR("Get error[%d]", err);
		return;
	}

    MsgQueue_Send1(msgId, "1");
    MsgQueue_Send1(msgId, "2");

    while(1)
    {
        if((err = MsgQueue_Recv1(msgId, msgData)) < 0)
        {
            // PRINT_ERROR("Recv error[%d]", err);
        }
        // PRINT_DEBUG();
        msgDataNum = atoi(msgData);
        switch(msgDataNum)
        {
            case 1:
                RatedLimit_Refresh(RATED_LIMIT_TYPE_CHRG, &firstFlagChrg); 
                break;

            case 2:
                RatedLimit_Refresh(RATED_LIMIT_TYPE_DISC, &firstFlagDisc); 
                break;
            
            default:
                PRINT_WARN("error msgDataNum[%d]", msgDataNum);
                break;
        }
    }
}


#endif

